package edu.ncet.desktop.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.extjs.gxt.ui.client.data.BaseModel;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.button.ButtonBar;
import com.extjs.gxt.ui.client.widget.button.ToggleButton;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.LabelField;
import com.extjs.gxt.ui.client.widget.form.TextArea;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.layout.TableLayout;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;

import edu.ncet.desktop.shared.AnswerSheetModel;
import edu.ncet.desktop.shared.QuestionModel;

public abstract class AbstractExaminationPanel extends ContentPanel
{

	protected TextField<String> ans1Text;
	protected TextField<String> ans2Text;
	protected TextField<String> ans3Text;
	protected TextField<String> ans4Text;
	protected AnswerSheetModel answerSheet = new AnswerSheetModel();
	protected ComboBox<AnswerComboModel> studentAnswerCombo;

	protected TextArea questionText;
	protected LabelField questionNumberLable;
	protected List<QuestionModel> questionSheet = null;
	protected List<Integer> markedQuestions = new ArrayList<Integer>();
	protected QuestionModel currentQuestion = null;
	protected Integer currentQuestionIndex = 0;

	protected Integer timerStop = new Integer( 0 );
	protected Button nextButton;
	protected Button priviousButton;
	protected Timer timer;
	protected ListStore<NavigateToQuestionComboModel> navigatoToQuestionStore;
	protected ComboBox<NavigateToQuestionComboModel> navigateToQuestionCombo;
	protected ToggleButton markButton;
	protected LabelField messageToStudent;

	final String IMAGE_UNANSWERED = "unanswered";
	final String IMAGE_MARKED = "marked";
	final String IMAGE_ANSWERED = "answered";
	protected boolean confirmOk;

	public AbstractExaminationPanel()
	{
		setHeaderVisible(false);
		getInfoPanel();
		getQuestionTextArea();
		getOptionAnswerPanel();
		getStudentAnswerPanel();
		getActionsPanel();
		loadQuestionPaper();
	}

	private void getInfoPanel()
	{
		ContentPanel infoPanel = new ContentPanel( new TableLayout( 4 ) );
		infoPanel.setHeaderVisible( false );
		infoPanel.setWidth( 1000 );

		getNavigateToQuestionCombo();

		questionNumberLable = new LabelField( "Question : " );
		questionNumberLable.setStyleAttribute( "color", "#E81302" );
		questionNumberLable.setStyleAttribute( "fontWeight", "bold" );
		final LabelField time = new LabelField( "Time Remaining :" );

		timer = new Timer()
		{
			@Override
			public void run()
			{
				--timerStop;
				Integer hour = timerStop / 3600;
				Integer minute = ( timerStop - hour * 3600 ) / 60;
				Integer seconds = timerStop - ( hour * 3600 ) - ( minute * 60 );
				if ( hour == 0 && minute == 0 && seconds == 0 )
				{
					finishExam( true );
					cancel();
				}
				time.setValue( "Time Remaining : " + hour.toString() + " : " + minute.toString() + " : " + seconds.toString() );
			}
		};

		timer.scheduleRepeating( 1000 );
		infoPanel.add( questionNumberLable );
		navigateToQuestionCombo.setStyleAttribute( "margin", "0px 20px 0px 5px" );
		infoPanel.add( navigateToQuestionCombo );
		HorizontalPanel horizontalPanel = new HorizontalPanel();
		messageToStudent = new LabelField( " " );
		messageToStudent.setStyleAttribute( "color", "#0D5301" );
		horizontalPanel.add( messageToStudent );
		horizontalPanel.setWidth( 600 );
		infoPanel.add( horizontalPanel );
		infoPanel.add( time );
		add( infoPanel );
	}

	private void getActionsPanel()
	{
		ButtonBar bar = new ButtonBar();
		bar.setSpacing( 20 );
		bar.setWidth( 1000 );
		nextButton = new Button( "Next", new SelectionListener<ButtonEvent>()
		{
			@Override
			public void componentSelected( ButtonEvent ce )
			{
				displayQuestionNumber( ++currentQuestionIndex );
			}
		} );

		priviousButton = new Button( "Previous", new SelectionListener<ButtonEvent>()
		{
			@Override
			public void componentSelected( ButtonEvent ce )
			{
				displayQuestionNumber( --currentQuestionIndex );
			}
		} );

		markButton = new ToggleButton( "Mark", new SelectionListener<ButtonEvent>()
		{
			@Override
			public void componentSelected( ButtonEvent ce )
			{
				if ( markButton.isPressed() )
				{
					logInfoToStudent( "Question No. " + getCurrentIndex1based() + " is marked." );
					markedQuestions.add( currentQuestion.getQuesNo() );
				}
				else
				{
					logInfoToStudent( "Question No. " + getCurrentIndex1based() + " is unmarked." );
					markedQuestions.remove( currentQuestion.getQuesNo() );
				}
			}
		} );

		bar.add( priviousButton );
		bar.add( nextButton );
		bar.add( markButton );
		bar.add( new Button( "Finish", new SelectionListener<ButtonEvent>()
		{
			@Override
			public void componentSelected( ButtonEvent ce )
			{
				finishExam( false );
			}

		} ) );
		add( bar );
	}

	private void getNavigateToQuestionCombo()
	{
		navigateToQuestionCombo = new ComboBox<NavigateToQuestionComboModel>();
		navigatoToQuestionStore = new ListStore<NavigateToQuestionComboModel>();
		navigateToQuestionCombo.setTemplate( getFlagTemplate( GWT.getModuleBaseURL() ) );
		navigateToQuestionCombo.setDisplayField( "display" );
		navigateToQuestionCombo.setTypeAhead( true );
		navigateToQuestionCombo.setTriggerAction( TriggerAction.ALL );
		navigateToQuestionCombo.setWidth( 70 );
		navigateToQuestionCombo.setStore( navigatoToQuestionStore );
	}

	private void getStudentAnswerPanel()
	{
		TableLayout layout = new TableLayout( 2 );
		ContentPanel studentAnsPanel = new ContentPanel( layout );
		studentAnsPanel.setWidth( 1000 );
		studentAnsPanel.setHeaderVisible( false );
		studentAnsPanel.setFrame( true );

		LabelField studentAnsLabel = new LabelField( "Answer" );
		studentAnswerCombo = new ComboBox<AnswerComboModel>();
		studentAnswerCombo.setEditable( false );
		studentAnswerCombo.addListener( Events.Select, new Listener<BaseEvent>()
		{
			public void handleEvent( BaseEvent be )
			{
				studentAnswerUpdateAction();
			}
		} );
		studentAnswerCombo.setDisplayField( "display" );
		ListStore<AnswerComboModel> store = new ListStore<AnswerComboModel>();
		store.add( new AnswerComboModel( "A" ) );
		store.add( new AnswerComboModel( "B" ) );
		store.add( new AnswerComboModel( "C" ) );
		store.add( new AnswerComboModel( "D" ) );
		studentAnswerCombo.setStore( store );
		studentAnsPanel.add( studentAnsLabel );
		studentAnsPanel.add( studentAnswerCombo );
		add( studentAnsPanel );
	}

	private void getOptionAnswerPanel()
	{
		TableLayout layout = new TableLayout( 4 );
		ContentPanel optionAnsPanel = new ContentPanel( layout );
		optionAnsPanel.setSize( 1000, 62 );
		optionAnsPanel.setHeaderVisible( false );
		optionAnsPanel.setFrame( true );
		LabelField ans1Label = new LabelField( "(A)" );
		ans1Text = new TextField<String>();
		ans1Text.setWidth( 468 );

		LabelField ans2Label = new LabelField( "(B)" );
		ans2Text = new TextField<String>();
		ans2Text.setWidth( 468 );

		LabelField ans3Label = new LabelField( "(C)" );
		ans3Text = new TextField<String>();
		ans3Text.setWidth( 468 );

		LabelField ans4Label = new LabelField( "(D)" );
		ans4Text = new TextField<String>();
		ans4Text.setWidth( 468 );

		optionAnsPanel.add( ans1Label );
		optionAnsPanel.add( ans1Text );

		optionAnsPanel.add( ans2Label );
		optionAnsPanel.add( ans2Text );

		optionAnsPanel.add( ans3Label );
		optionAnsPanel.add( ans3Text );

		optionAnsPanel.add( ans4Label );
		optionAnsPanel.add( ans4Text );

		add( optionAnsPanel );
	}

	private void getQuestionTextArea()
	{
		questionText = new TextArea();
		questionText.setSize( 1000, 320 );
		questionText.setReadOnly( true );
		add( questionText );
	}

	protected void enableDisableButtons()
	{
		if ( currentQuestionIndex == 0 )
			priviousButton.setEnabled( false );
		else
			priviousButton.setEnabled( true );

		if ( currentQuestionIndex == questionSheet.size() - 1 )
			nextButton.setEnabled( false );
		else
			nextButton.setEnabled( true );
	}

	private native String getFlagTemplate( String base ) /*-{
		return  [ 
		'<tpl for=".">', 
		'<div class="x-combo-list-item"><img src="' + base + 'resources/local/icons/{[values.imageName]}.png"> {[values.display]}</div>', 
		'</tpl>' 
		].join("");
	}-*/;

	protected Integer getCurrentIndex1based()
	{
		return currentQuestionIndex + 1;
	}

	protected void removeAllWidgets( ContentPanel panel )
	{
		panel.removeAll();
		panel.layout();
	}

	protected void logInfoToStudent( String msg )
	{
		messageToStudent.setText( msg );
	}

	public void setQuestionSheet( List<QuestionModel> result )
	{
		this.questionSheet = result;
	}

	public void createAnswerSheet()
	{
		answerSheet.setAnswerSheet( new HashMap<Integer, String>() );
	}

	public void setQuestionPaperTiming( Integer timing )
	{
		this.timerStop = timing;
	}

	protected abstract void studentAnswerUpdateAction();

	protected abstract void finishExam( boolean isForced );

	protected abstract void displayQuestionNumber( Integer integer );

	protected abstract void loadQuestionPaper();
}

class AnswerComboModel extends BaseModel
{
	private static final long serialVersionUID = 1L;

	public AnswerComboModel( String display )
	{
		set( "display", display );
	}
}

class NavigateToQuestionComboModel extends BaseModel
{
	private static final long serialVersionUID = 1L;

	public NavigateToQuestionComboModel( String display, String imageName )
	{
		set( "display", display );
		set( "imageName", imageName );
	}
}
